#!/usr/bin/env python3

import configparser
import http.client
import json
import logging
import time
from urllib.parse import urlencode


def fetch_metric(metric_id: str, query: str) -> float:
    logging.info("Fetching %s", metric_id)
    params = urlencode({"query": query})
    conn = http.client.HTTPConnection("localhost:9090")
    conn.request("GET", "/api/v1/query?" + params)
    response = conn.getresponse()
    if response.status != 200:
        raise Exception(
            f"Failed to request {metric_id} from Prometheus: {response.status} {response.reason}"
        )
    raw_bytes = response.read()
    conn.close()
    data = json.loads(raw_bytes)
    if data["status"] != "success":
        raise Exception("Failed to request {metric_id}: {raw_bytes.decode()}")
    return float(data["data"]["result"][0]["value"][1])


def push_metric(metric_id: str, metric_value: float, page_id: str, oauth_token: str) -> None:
    conn = http.client.HTTPSConnection("api.statuspage.io")
    params = json.dumps({"data": {"timestamp": time.time(), "value": metric_value}})
    headers = {"Content-Type": "application/json", "Authorization": "OAuth " + oauth_token}
    conn.request(
        "POST", "/v1/pages/" + page_id + "/metrics/" + metric_id + "/data.json", params, headers
    )
    response = conn.getresponse()
    if not (response.status >= 200 and response.status < 300):
        raise Exception(
            f"Failed to push {metric_id} to statuspage.io: {response.status} {response.reason}"
        )
    logging.info("Wrote %s: %s", metric_id, response.read().decode())
    conn.close()


def update_metric(metric_id: str, query: str, page_id: str, oauth_token: str) -> None:
    metric_value = fetch_metric(metric_id, query)
    push_metric(metric_id, metric_value, page_id, oauth_token)


def main() -> None:
    logging.basicConfig(format="%(asctime)s statuspage-pusher: %(message)s", level=logging.INFO)

    secrets_file = configparser.RawConfigParser()
    secrets_file.read("/etc/zulip/zulip-secrets.conf")

    oauth_token = secrets_file.get("secrets", "statuspage_token")
    if oauth_token is None:
        raise RuntimeError("statuspage_token secret is required")

    config_file = configparser.RawConfigParser()
    config_file.read("/etc/zulip/zulip.conf")
    page_id = config_file.get("statuspage", "page_id")
    if page_id is None:
        raise RuntimeError("statuspage_page_id secret is required")

    metrics_file = configparser.RawConfigParser()
    metrics_file.read("/etc/zulip/statuspage.conf")
    metrics = metrics_file["metrics"]

    while True:
        for metric_id in metrics:
            try:
                update_metric(metric_id, metrics.get(metric_id), page_id, oauth_token)
            except Exception as e:
                logging.exception(e)
        time.sleep(30)


if __name__ == "__main__":
    main()
